#include "ClientFunc.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int LoginFace()
{  
    printf("=============聊天室登录=====================\n");
    printf("1、注册\n");
    printf("2、登录\n");
    printf("=================================================\n");
    printf("请选择你要的功能：");
    int choice = 0;
    scanf("%d",&choice);
    return choice* (-1);
}

// 注册
MSG SignUp( char *MyName)
{
    MSG m;
    m.flag = SIGNUP; //注册用户名
    printf("================注册新用户====================\n");
    printf("请输入你的用户名:");
    scanf("%s",m.FromName);
    printf("请输入你的密码：");
    scanf("%s",m.Content);
    printf("===============================================\n");

    strcpy(MyName,m.FromName); //发送消息 m 到一个 TCP 客户端 c，消息的大小为 sizeof(m)
    return m;


}

bool IsSignUpSuccess(MSG *m)
{   
     
    if(strcmp(m->Content,"注册成功") == 0)
    {
        printf("注册成功！欢迎来到聊天室\n");
        return true;
    }
    else
    {
        printf("注册错误:%s\n",m->Content);
        return false;
    } 

}

MSG Login(char*MyName)
{
    MSG m;
    m.flag = LOGIN; //注册用户名
    printf("================登录用户====================\n");
    printf("请输入你的用户名:");
    scanf("%s",m.FromName);
    printf("请输入你的密码：");
    scanf("%s",m.Content);
    printf("===============================================\n");

    strcpy(MyName,m.FromName); //发送消息 m 到一个 TCP 客户端 c，消息的大小为 sizeof(m)
    return m;
}

bool IsLoginSuccess(MSG *m)
{   
    if(strcmp(m->Content,"success") == 0)
    {
        printf("登录成功！欢迎来到聊天室\n");
        return true;
    }
    else
    {
        printf("登录错误:%s\n",m->Content);
        return false;
    } 
}

int Interface()
{
    printf("=============欢迎来到聊天室=====================\n");
    printf("1、私聊\n");
    printf("2、广播\n");
    printf("3、查看在线用户\n");
    printf("4、文件发送\n");
    printf("5、我的网盘\n");
    printf("6、我的好友\n");
    printf("7、我的群聊\n");
    printf("=================================================\n");
    printf("请选择你要的功能：");
    int choice = 0;

    scanf("%d",&choice);
    return choice;
}

MSG ChatBroadCast() //函数的声明，指定了函数的返回类型为 MSG，函数名为 ChatBroadCast，并且不接受任何参数。
{   
    MSG m; //声明了一个名为 m 的变量，类型为 MSG，用于存储消息
    m.flag = BROADCAST; //给消息的 flag 属性赋值为 BROADCAST 用于标识消息类型
    printf("请输入你要发送的消息：");
    scanf("%s",m.Content); //从用户输入中读取字符串，并将其存储在消息结构体 m 的 Content 成员中
    return m; //返回存储了用户输入消息的消息结构体 m
}

MSG GetServerOnlineList()
{
    MSG m;
    m.flag = ONLINELIST;
    return m;
}

MSG ApplyForFriendship()
{   
     MSG m;
     m.flag = ADDFRIEND;
     printf("请输入你要加的好友：");
     scanf("%s",m.ToName);
     return m;
}

// 私聊
MSG ChatToClient()
{
        MSG m;
        m.flag = CHAT;
        printf("请输入你要发送的用户名称：");
        scanf("%s",m.ToName);
        printf("请输入你要发送的消息：");
        scanf("%s",m.Content);
        return m;   
}
//好友间聊天
MSG ChatToFriend()
{
        MSG m;
        m.flag = FRIEND;
        printf("请输入你要发送的好友名称：");
        scanf("%s",m.ToName);
        printf("请输入你要发送的消息：");
        scanf("%s",m.Content);
        return m;   
}

void ShowOnlineList(MSG *m) //函数的声明，指定了函数的返回类型为 void，函数名为 ShowOnlineList，接受一个指向 MSG 结构体的指针作为参数
{
    char str[ContentSize] = {0}; //声明了一个名为 str 的字符数组，长度为 ContentSize，并初始化为全零。这个数组用来存储消息中的内容
    strcpy(str,m->Content); //将消息结构体 m 中的内容复制到字符数组 str 中
    char *dest = strtok(str,","); //使用 strtok 函数将字符串 str 按照逗号 , 分割，得到第一个子字符串的指针 dest
    int count = 1;
    while(dest != NULL)
    {
        printf("%d:%s\n",count++,dest);
        dest = strtok(NULL,","); //使用 strtok 函数获取下一个子字符串。
    }

}

MSG SendFile()
{
     MSG m;
     m.flag = SENDFILE;
     printf("请输入你要发送的文件路径：");
     scanf("%s",m.Content);
     printf("请输入你要发送的用户：");
     scanf("%s",m.ToName);
     return m;
}

char *GetFileNameFromPath(const char *filePath)
{   
    char str[ContentSize] = {0};
    strcpy(str,filePath);

    char*dest = strtok(str,"/"); //用于字符串分割的函数，将字符串按照指定的分隔符进行分割，并返回分割后的第一个子字符串
    char*fileName = NULL;
    while(dest != NULL) // strtok 函数来遍历字符串 str 中的所有子字符串，并将每个子字符串赋值给 fileName 变量，直到没有更多的子字符串为止
    {   
        fileName = dest;
        dest = strtok(NULL,"/"); //让 strtok 函数继续从上一次分割的位置继续分割字符串
    }
    char* result = strdup(fileName); //堆上复制字符串
    return result;
}

void WriteToLocal(MSG * m)
{   
    int size = 0;
    memcpy(&size,m->Content,sizeof(int));
    char fileName[NameSize] = {0};
    strcpy(fileName,m->Content + 4);

    char filePath[ContentSize] = {0};
    printf("%s\n",filePath);
    sprintf(filePath,"./%s",fileName);
    FILE *f = fopen(filePath,"a");
    fwrite(m->Content+24,size,1,f);
    fclose(f);

}

void ServerToClient(MSG * m)
{   
    int allSize = 0;
    memcpy(&allSize,m->ToName,sizeof(int));
    int size = 0;
    memcpy(&size,m->Content,sizeof(int));
    int bytesWritten = 0;
    bytesWritten += size;
    char fileName[NameSize] = {0};
    strcpy(fileName,m->Content1);
    char filePath[ContentSize] = {0};
    char file[1024] = "./Client/本地文件";
    sprintf(filePath,"%s/%s",file,fileName);
    FILE *f = fopen(filePath,"a");
    fwrite(m->Content+24,size,1,f);
    fclose(f);
    float progress = (float)bytesWritten/ allSize* 100;
    printf("\rDown: %.2f%%",progress);
    fflush(stdout);
}

int CloudInterface()
{
    printf("===========================我的网盘=================================\n");
    printf("1、查看网盘文件\n");
    printf("2、上传文件\n");
    printf("3、下载文件\n");
    printf("4、退回到主界面\n");
    printf("====================================================================\n");
    printf("请输入你的选择:");
    int choice = 0;
    scanf("%d",&choice);
    return FILELIST + choice -1;
   
}

int FriendInterface()
{
    printf("============================我的好友=================================\n");
    printf("1、好友列表\n");
    printf("2、添加好友\n");
    printf("3、好友申请\n");
    printf("4、删除好友\n");
    printf("5、发送消息\n");
    printf("6、返回\n");
    printf("=====================================================================\n");
    printf("请输入你的选择:");
    int choice = 0;
    scanf("%d",&choice);
    return choice + FRIENDLIST -1;
}
int GroupChatInterface()
{
    printf("============================我的群聊=================================\n");
    printf("1、群聊列表\n");
    printf("2、创建群聊\n");
    printf("3、群聊申请\n");
    printf("4、加入群聊\n");
    printf("5、退出群聊\n");
    printf("6、拉入群聊\n");
    printf("7、返回\n");
    printf("=====================================================================\n");
    printf("请输入你的选择:");
    int choice = 0;
    scanf("%d",&choice);
    return choice + GROUPCHATLIST -1;
}
MSG UpLoadFile()
{   
    MSG m;
    m.flag = UPLOAD;
    printf("请输入要上传的文件路径:");
    scanf("%s",m.Content);
    return m;
}

char** Split(const char *str,const char*delim,int *size)
 {
     char *splitStr = strdup(str);

     char**result = (char**)malloc(sizeof(char*) * 50);
     if(result == NULL)
     {
        printf("Split malloc error!\n");
        return NULL;
     }
    
    int count = 0;
    char*dest = strtok(splitStr,delim) ;
    while(dest != NULL)
    {
        result[count++] = strdup(dest);
        dest = strtok(NULL,delim);
    }
     free(splitStr);
     *size = count;
     return result;
 }

void FreeStrList(char** strList,int size)
{
    for(int i = 0;i < size;i++)
    {
        free(strList[i]);
    }
    free(strList);
}

void ShowFileList(MSG *m)
{    
    if(strcmp(m->Content,"FileError") == 0)
    {
        printf("获取网盘文件失败!\n");
        return;
    }
    

    int fileCount = 0;
    char** file = Split(m->Content,",",&fileCount);
    for(int i = 0;i < fileCount;i++)
    {   
        int count = 0;
        char**fileInfo = Split(file[i],";",&count);
        if(count != 2)
        {    
             FreeStrList(fileInfo,count);
             continue;
        }
        printf("%d : 文件名: |%s|  文件大小:|%s|\n",i+1,fileInfo[0],fileInfo[1]);
        FreeStrList(fileInfo,count);
    }
    FreeStrList(file,fileCount);
    
}

struct PacketFile
{
    FILE *f;
    long FileSize;
    long currentPosition;
};

PackFile *PacketFileInit(const char *FilePath) //函数的声明，指定了函数的返回类型为 PackFile*，函数名为 PacketFileInit，接受一个指向常量字符的指针 FilePath 作为参数，表示文件路径。
{   
    PackFile *pf = (PackFile*)malloc(sizeof(PackFile)); //使用 malloc 函数分配内存，大小为 PackFile 结构体的大小，并将其强制类型转换为 PackFile* 类型的指针。这个指针 pf 指向分配的内存块，用于存储 PackFile 结构体的数据
    if(pf == NULL)
    {
        printf("PackerFileInit malloc error!\n");
        return NULL;
    }

    pf->f = fopen(FilePath,"r"); //打开指定路径的文件，以只读方式打开，并将文件指针赋值给 pf->f
    if(pf->f == NULL)
    {
        printf("打开|%s|文件失败！\n",FilePath);
        free(pf);
        return NULL;
    }

    fseek(pf->f,0,SEEK_END); //将文件指针移到文件末尾，以便获取文件大小
     pf->FileSize = ftell(pf->f); //获取文件大小，并将其保存到 pf->FileSize 中。
    fseek(pf->f,0,SEEK_SET); //将文件指针移回文件开头，以便后续读取文件内容

    pf->currentPosition = 0; //将当前位置初始化为文件开头
    return pf;
    
}

void ReadFromFile(PackFile *f, void *p, int *size) //函数的声明，指定了函数的返回类型为 void，函数名为 ReadFromFile，接受一个 PackFile 结构体指针 f，一个指向内存的指针 p，以及一个整型指针 size 作为参数。
{
    if(*size + f->currentPosition > f->FileSize) //检查要读取的数据大小加上当前位置是否超过了文件大小。如果超过了，就将要读取的大小调整为剩余的文件大小
    {
        *size = f->FileSize -f->currentPosition; //如果要读取的数据大小超过了文件剩余大小，就将 size 调整为剩余的文件大小。


    }
    fread(p,*size,1,f->f); //使用 fread 函数从文件中读取数据，将读取的数据存储到内存指针 p 所指向的位置，读取的大小为 size，每次读取一个数据块
    f->currentPosition += *size; //将文件指针移动到已读取的位置之后，以便下一次读取
}

bool IsFileEnd(PackFile *f) //这是函数的声明，指定了函数的返回类型为布尔值 bool，函数名为 IsFileEnd，接受一个 PackFile 结构体指针 f 作为参数
{   
    return f->currentPosition == f->FileSize; //feof 函数用于检查文件流的结束标志。如果文件已经结束，则 feof 返回非零值，否则返回零。将 feof 返回的结果与零进行比较，如果不等于零，则说明文件已经到达末尾，返回 true；否则返回 false
    
}
MSG DownLoadFile()
{   
    MSG m ;
    m.flag = DOWNLOAD;
    printf("请输入你想要下载的文件名:\n");
    scanf("%s",m.Content);
    return m;
    
}
void ShowFriendMessages(MSG *m)
{    
     char buffer1[20][20] = {0};
     char buffer2[20][20] = {0};
     char buffer3[20][20] = {0};
     char*token1;
     char*token2;
     char*token3;
     int a = 0,b = 0,c = 0;
     token1 = strtok(m->Content1,",");
     while(token1 != NULL)
     {  
        strcpy(buffer1[a],token1);
        a ++;
        token1 = strtok(NULL,",");
     }
     token2 = strtok(m->Content2,",");
     while(token2 != NULL)
     {
        strcpy(buffer2[b],token2);
        b ++;
        token2 = strtok(NULL,",");
     }
     token3 = strtok(m->Content3,",");
     while(token3 != NULL)
     {
        strcpy(buffer3[c],token3);
        c ++;
        token3 = strtok(NULL,",");
     }
     for(int i = 0;i < a;i++)
     {
        printf("|%d| 发送人:%s 消息:%s 时间:%s\n",i+1,buffer1[i],buffer2[i],buffer3[i]);
     }
}
void ShowGroupChatList(MSG *m)
{    
     char buffer1[20][20] = {0};
     char buffer2[20][20] = {0};
     char buffer3[20][20] = {0};
     char*token1;
     char*token2;
     char*token3;
     int f = atoi(m->ToName);
     int a = 0,b = 0,c = 0;
     token1 = strtok(m->Content,",");
     while(token1 != NULL)
     {  
        strcpy(buffer1[a],token1);
        a ++;
        token1 = strtok(NULL,",");
     }
     token2 = strtok(m->Content1,",");
     while(token2 != NULL)
     {
        strcpy(buffer2[b],token2);
        b ++;
        token2 = strtok(NULL,",");
     }
     token3 = strtok(m->Content2,",");
     while(token3 != NULL)
     {
        strcpy(buffer3[c],token3);
        c ++;
        token3 = strtok(NULL,",");
     }
    
     for(int i = 0;i < f;i++)
     {
        printf("|%d| 群名:%s 群号:%s 群主:%s\n",i+1,buffer1[i],buffer2[i],buffer3[i]);
     }
}

void ShowGroupChatApply(MSG*m)
{
     char buffer1[20][20] = {0};
     char buffer2[20][20] = {0};
     char buffer3[20][20] = {0};
     char*token1;
     char*token2;
     char*token3;
     int a = 0,b = 0,c = 0;
     token1 = strtok(m->Content,",");
     while(token1 != NULL)
     {  
        strcpy(buffer1[a],token1);
        a ++;
        token1 = strtok(NULL,",");
     }
     token2 = strtok(m->Content1,",");
     while(token2 != NULL)
     {
        strcpy(buffer2[b],token2);
        b ++;
        token2 = strtok(NULL,",");
     }
     token3 = strtok(m->Content2,",");
     while(token3 != NULL)
     {
        strcpy(buffer3[c],token3);
        c ++;
        token3 = strtok(NULL,",");
     }
    
     for(int i = 0;i < a;i++)
     {
        printf("|%d| 群名:%s 群号:%s 申请人:%s\n",i+1,buffer1[i],buffer2[i],buffer3[i]);
     }
}

void ClearPacketFile(PackFile*f)
{
      fclose(f->f);
      free(f);
}
